package sess

import (
	"errors"
	"fmt"
	"net"
	"src/zeus/dbservice"
	"src/zeus/iserver"
	"src/zeus/logger"
	"src/zeus/msgdef"
	. "src/zeus/msghandler"
	"sync"
)

// IConnNotify 连接状态发生改变得到通知
type IConnNotify interface {
	//连接被关闭的时候(这个回调会在任意协程上，所以需要注意安全)
	connErr(sess iserver.ISess)
	//会话的验证回调 如果是连接客户端的上层需要重载实现验证逻辑，失败就返回错误，底层会关闭连接
	verifySess(msg msgdef.ISessionVerifyReqMsg, sess iserver.ISess) error
}

type ISessionVerifyHandler interface {
	VerifyMessage(im msgdef.ISessionVerifyReqMsg, sess iserver.ISess) bool
}

func newSessMgr(msghandlers *MsgHandler) *SessMgr {
	sm := &SessMgr{
		MsgHandler:      msghandlers,
		_encryptEnabled: false,
	}
	sm.SetVerifyHandler(sm)
	return sm
}

// RawMsg 对象
type RawMsg struct {
	MsgID int
	Msg   []byte
}

// SessMgr 作为服务器 我管理客户端会话的管理器 Sess; 这里的客户端 包含 服务会话和玩家会话
type SessMgr struct {
	*MsgHandler

	// sessesByAddr sync.Map
	sessesByID sync.Map
	//oldSessesByID *sync.Map

	_encryptEnabled bool
	verifyHandler   ISessionVerifyHandler
}

func (mgr *SessMgr) VerifyMessage(im msgdef.ISessionVerifyReqMsg, sess iserver.ISess) bool {
	msg := im.(*msgdef.ClientVerifyReq)
	var verify = false
	// 验证 服务器会话直接验证通过, 玩家客户端会话需要验证token
	if msg.Source != msgdef.ClientMSG {
		logger.Info("[SessMgr] VerifyMessage SrvClientSess Source: ", msg.Source, " pid: ", msg.PID, " Token: ", msg.Token)
		// if im.GetSessSToken() == iserver.GetSrvInst().GetCurSrvInfo().Token {
		// 	verify = true
		// }
		verify = true
	} else {
		verify = dbservice.NewSessionUtil(msg.PID).VerifyToken(msg.Token, sess.RemoteAddr())
		logger.Debugf(logger.LogKey_LoginFlow, "[SessMgr] VerifyMessage UserSess Source:%d pid:%d Token:%s %t ", msg.Source, msg.PID, msg.Token, verify)
	}

	return verify
}

func (mgr *SessMgr) SetVerifyHandler(handler ISessionVerifyHandler) {
	if handler == nil {
		handler = mgr
	}
	mgr.verifyHandler = handler
}

// SetEncryptEnabled 设置加密模式
func (mgr *SessMgr) SetEncryptEnabled() {
	mgr._encryptEnabled = true
}

func (mgr *SessMgr) acceptConn(conn net.Conn) {
	sess := mgr.newSess(conn)
	sess.Start(nil)
}

func (mgr *SessMgr) verifySess(msgContent msgdef.ISessionVerifyReqMsg, sess iserver.ISess) error {

	if sess.IsVerified() {
		return errors.New("sess had verified but receive a clientvetifyreq message ")
	}
	if !mgr.verifyHandler.VerifyMessage(msgContent, sess) {
		// 返回失败的消息
		sess.SendNow(&msgdef.ClientVerifyFailedRet{})
		return errors.New(fmt.Sprintln("sess verified failed ", msgContent.GetSessVerifyPID()))
	}
	sess.SetVerify()
	sess.SetID(msgContent.GetSessVerifyPID())
	sess.SetType(iserver.ServerType(msgContent.GetSource()))
	mgr.putSess(sess)
	logger.Infof("[SessMgr]SessVerify isClient:%v type:%d;uid:%d;", sess.IsSrvToClientSess(), sess.GetType(), msgContent.GetSessVerifyPID())
	return nil
}

func (mgr *SessMgr) close() {
	//此处会不会死锁？
	mgr.sessesByID.Range(func(_, sess interface{}) bool {
		sess.(iserver.ISess).Close()
		return true
	})

}

func (mgr *SessMgr) newSess(conn net.Conn) iserver.ISess {
	return newSess(conn, mgr, mgr._encryptEnabled, isSrvToClientSessionFalse)
}

func (mgr *SessMgr) putSess(sess iserver.ISess) {

	sess.SetMsgHandler(mgr.MsgHandler)
	for {
		if v, loaded := mgr.sessesByID.LoadOrStore(sess.GetID(), sess); loaded {
			oldSess := v.(iserver.ISess)
			oldSess.Send(&msgdef.UserDuplicateLoginNotify{}) //会话重复
			oldSess.SetDuplicate()
			//对方是客户端,则需要发送Lobby 网络断开消息,但是这里无法判断
			if oldSess.IsSrvToClientSess() {
				logger.Debug(logger.LogKey_LoginFlow, "SessMgr::putSess -> 顶号登录 srvToClientSess: oldSess=", oldSess.GetID(), oldSess.GetType(),
					oldSess.IsPlayerClientSess())
				//这里应该通知 lobby服务器的,不过应该放到逻辑层处理; 这里先不处理;
				//oldSess.SendNow(&protoMsg.PlayerLogoutSrv{})//断开连接通知
				//oldSess.SendNow(&protoMsg.PlayerOffineSrv{})//彻底离线销毁通知
			}
			mgr.removeSess(oldSess)
		} else {
			break
		}
	}

	// mgr.sessesByAddr.Store(sess.RemoteAddr(), sess)
	//logger.Info("[SessMgr] putSess ", sess.RemoteAddr(), "ID: ", sess.GetID())

	// if os, ok := mgr.oldSessesByID.Load(sess.GetID()); ok {
	// 	sess.FetchBacklog(os.(iserver.ISess))
	// 	mgr.oldSessesByID.Delete(sess.GetID())
	// }
}

// 删除连接
func (this *SessMgr) removeSess(sess iserver.ISess) {
	this.sessesByID.CompareAndDelete(sess.GetID(), sess)
	sess.SetMsgHandler(nil)
}

// func (mgr *SessMgr) removeSess(id uint64) {

// 	if id == 0 {
// 		return
// 	}

// 	ios, ok := mgr.sessesByID.Load(id)
// 	if !ok {
// 		// log.Error("remove sess but sess id is not in list ", id)
// 		return
// 	}
// 	mgr.sessesByID.Delete(id)
// 	// mgr.sessesByAddr.Delete(ios.(iserver.ISess).RemoteAddr())
// 	//mgr.oldSessesByID.Store(id, ios)

// 	logger.Debug(logger.LogKey_LoginFlow, "[SessMgr] removeSess sess ", ios.(iserver.ISess).RemoteAddr(), " id: ", id)

// 	// time.AfterFunc(90*time.Second, func() {
// 	// 	mgr.oldSessesByID.Delete(id)
// 	// })

// 	ios.(iserver.ISess).Close()
// }

func (mgr *SessMgr) getSessByID(id uint64) iserver.ISess {

	is, ok := mgr.sessesByID.Load(id)
	if !ok {
		return nil
	}
	if is.(iserver.ISess).IsClosed() {
		return nil
	}
	return is.(iserver.ISess)
}

func (mgr *SessMgr) connErr(sess iserver.ISess) {
	//logger.Info("[SessMgr::connErr] id :", id)
	// mgr.removeSess(id)
	mgr.sessesByID.CompareAndDelete(sess.GetID(), sess)
}

// 遍历所有被动连接，返回false就退出遍历
func (mgr *SessMgr) RangeSess(f func(sess iserver.ISess) bool) {
	mgr.sessesByID.Range(func(key, value any) bool {
		return f(value.(iserver.ISess))
	})
}
